export * from "./base64";
declare var BigInt: (param: any) => bigint;
function checkBigInt() {
  try {
    if (BigInt) return BigInt;
  } catch (error) { }
  return (param: any) => { return parseInt(param) as any as bigint; };
}
var BigInt = checkBigInt();
/** 雪花算法获取id */
export class Genid {
  private BaseTime: bigint;
  private WorkerId: bigint;
  private WorkerIdBitLength: bigint;
  private SeqBitLength: bigint;
  private MaxSeqNumber: bigint;
  private MinSeqNumber: bigint;
  private TopOverCostCount: bigint;
  private _TimestampShift: bigint;
  private _CurrentSeqNumber: bigint;
  private _LastTimeTick: bigint;
  private _TurnBackTimeTick: bigint;
  private _TurnBackIndex: bigint;
  private _IsOverCost: boolean;
  private _OverCostCountInOneTerm: bigint;

  /**
   *Creates an instance of Genid.
   * @author bubao
   * @param {{
   *     Method: 1, // 雪花计算方法，（1-漂移算法|2-传统算法），默认 1
   *     BaseTime: 1577836800000,  // 基础时间（ms 单位），不能超过当前系统时间
   *     WorkerId: Number, // 机器码，必须由外部设定，最大值 2^WorkerIdBitLength-1
   *     WorkerIdBitLength: 6,   // 机器码位长，默认值 6，取值范围 [1, 15](要求：序列数位长+机器码位长不超过 22)
   *     SeqBitLength: 6,   // 序列数位长，默认值 6，取值范围 [3, 21](要求：序列数位长+机器码位长不超过 22)
   *     MaxSeqNumber: 5, // 最大序列数（含），设置范围 [MinSeqNumber, 2^SeqBitLength-1]，默认值 0，表示最大序列数取最大值（2^SeqBitLength-1]）
   *     MinSeqNumber: 5, // 最小序列数（含），默认值 5，取值范围 [5, MaxSeqNumber]，每毫秒的前 5 个序列数对应编号 0-4 是保留位，其中 1-4 是时间回拨相应预留位，0 是手工新值预留位
   *     TopOverCostCount: 2000// 最大漂移次数（含），默认 2000，推荐范围 500-10000（与计算能力有关）
   * }} options
   * @memberof Genid
   */
  constructor (options?: GenidOptions) {
    // new Date().getTime() / iyq;
    if (typeof options != "object") {
      options = {};
    }
    while (!options.WorkerId || !(options.WorkerId > 0)) {
      // options.WorkerId = Math.floor(Math.random() * 123654) + 1;
      options.WorkerId = parseInt(new Date().getTime());
    }
    // 1.BaseTime
    if (!options.BaseTime || options.BaseTime < 0) {
      // options.BaseTime = 1577836800000;
      // options.BaseTime = 1;
      options.BaseTime = new Date().getTime();
    }
    // 2.WorkerIdBitLength
    if (!options.WorkerIdBitLength || !(options.WorkerIdBitLength > 0)) {
      options.WorkerIdBitLength = 6;
    }

    // 4.SeqBitLength
    const SeqBitLength = 6;
    if (!options.SeqBitLength || options.SeqBitLength < 0) {
      options.SeqBitLength = SeqBitLength;
    }
    // 5.MaxSeqNumber
    const MaxSeqNumber = (1 << SeqBitLength) - 1;
    if (options.MaxSeqNumber === undefined || !(options.MaxSeqNumber > 0)) {
      options.MaxSeqNumber = MaxSeqNumber;
    }
    // 6.MinSeqNumber
    const MinSeqNumber = 5;
    if (!options.MinSeqNumber || options.MinSeqNumber < 0) {
      options.MinSeqNumber = MinSeqNumber;
    }
    // 7.Others
    const topOverCostCount = 2000;
    if (!options.TopOverCostCount || options.TopOverCostCount < 0) {
      options.TopOverCostCount = topOverCostCount;
    }

    // this.Method = BigInt(options.Method == 2 ? 2 : 1);
    this.BaseTime = BigInt(options.BaseTime);
    this.WorkerId = BigInt(options.WorkerId);
    this.WorkerIdBitLength = BigInt(options.WorkerIdBitLength);
    this.SeqBitLength = BigInt(options.SeqBitLength);
    this.MaxSeqNumber = BigInt(options.MaxSeqNumber);
    this.MinSeqNumber = BigInt(options.MinSeqNumber);
    this.TopOverCostCount = BigInt(options.TopOverCostCount);

    const timestampShift = this.WorkerIdBitLength + this.SeqBitLength;
    const currentSeqNumber = this.MinSeqNumber;

    this._TimestampShift = timestampShift;
    this._CurrentSeqNumber = currentSeqNumber;

    this._LastTimeTick = BigInt(0);
    this._TurnBackTimeTick = BigInt(0);
    this._TurnBackIndex = BigInt(0);
    this._IsOverCost = false;
    this._OverCostCountInOneTerm = BigInt(0);
  }

  // // DoGenIDAction .
  // private DoGenIdAction(OverCostActionArg: bigint) {}
  // private BeginOverCostAction(useTimeTick: bigint) {}
  // private EndOverCostAction(useTimeTick: bigint) {
  //   // if m1._TermIndex > 10000 {
  //   //     m1._TermIndex = 0
  //   // }
  // }
  // private BeginTurnBackAction(useTimeTick: bigint) {}
  // private EndTurnBackAction(useTimeTick: bigint) {}

  public NextOverCostId() {
    const currentTimeTick = this.GetCurrentTimeTick();
    if (currentTimeTick > this._LastTimeTick) {
      // this.EndOverCostAction(currentTimeTick)
      this._LastTimeTick = currentTimeTick;
      this._CurrentSeqNumber = this.MinSeqNumber;
      this._IsOverCost = false;
      this._OverCostCountInOneTerm = BigInt(0);
      // this._GenCountInOneTerm = 0
      return this.CalcId(this._LastTimeTick);
    }
    if (this._OverCostCountInOneTerm >= this.TopOverCostCount) {
      // this.EndOverCostAction(currentTimeTick)
      this._LastTimeTick = this.GetNextTimeTick();
      this._CurrentSeqNumber = this.MinSeqNumber;
      this._IsOverCost = false;
      this._OverCostCountInOneTerm = BigInt(0);
      // this._GenCountInOneTerm = 0
      return this.CalcId(this._LastTimeTick);
    }
    if (this._CurrentSeqNumber > this.MaxSeqNumber) {
      this._LastTimeTick++;
      this._CurrentSeqNumber = this.MinSeqNumber;
      this._IsOverCost = true;
      this._OverCostCountInOneTerm++;
      // this._GenCountInOneTerm++

      return this.CalcId(this._LastTimeTick);
    }

    // this._GenCountInOneTerm++
    return this.CalcId(this._LastTimeTick);
  }

  public NextNormalId() {
    const currentTimeTick = this.GetCurrentTimeTick();
    if (currentTimeTick < this._LastTimeTick) {
      if (this._TurnBackTimeTick < BigInt(1)) {
        this._TurnBackTimeTick = this._LastTimeTick - BigInt(1);
        this._TurnBackIndex++;
        // 每毫秒序列数的前 5 位是预留位，0 用于手工新值，1-4 是时间回拨次序
        // 支持 4 次回拨次序（避免回拨重叠导致 ID 重复），可无限次回拨（次序循环使用）。
        if (this._TurnBackIndex > 4) {
          this._TurnBackIndex = BigInt(1);
        }
        // this.BeginTurnBackAction(this._TurnBackTimeTick);
      }
      return this.CalcTurnBackId(this._TurnBackTimeTick);
    }
    // 时间追平时，_TurnBackTimeTick 清零
    if (this._TurnBackTimeTick > BigInt(0)) {
      // this.EndTurnBackAction(this._TurnBackTimeTick);
      this._TurnBackTimeTick = BigInt(0);
    }

    if (currentTimeTick > this._LastTimeTick) {
      this._LastTimeTick = currentTimeTick;
      this._CurrentSeqNumber = this.MinSeqNumber;
      return this.CalcId(this._LastTimeTick);
    }

    if (this._CurrentSeqNumber > this.MaxSeqNumber) {
      // this.BeginOverCostAction(currentTimeTick);
      // this._TermIndex++
      this._LastTimeTick++;
      this._CurrentSeqNumber = this.MinSeqNumber;
      this._IsOverCost = true;
      this._OverCostCountInOneTerm = BigInt(1);
      // this._GenCountInOneTerm = 1

      return this.CalcId(this._LastTimeTick);
    }

    return this.CalcId(this._LastTimeTick);
  }

  private CalcId(useTimeTick: bigint) {
    const result = BigInt(useTimeTick << this._TimestampShift) + BigInt(this.WorkerId << this.SeqBitLength) + BigInt(this._CurrentSeqNumber);
    this._CurrentSeqNumber++;
    return result;
  }

  private CalcTurnBackId(useTimeTick: bigint) {
    const result = BigInt(useTimeTick << this._TimestampShift) + BigInt(this.WorkerId << this.SeqBitLength) + BigInt(this._TurnBackIndex);
    this._TurnBackTimeTick--;
    return result;
  }

  private GetCurrentTimeTick() {
    const millis = BigInt(new Date().valueOf());
    return millis - this.BaseTime;
  }

  private GetNextTimeTick() {
    let tempTimeTicker = this.GetCurrentTimeTick();
    while (tempTimeTicker <= this._LastTimeTick) {
      tempTimeTicker = this.GetCurrentTimeTick();
    }
    return tempTimeTicker;
  }

  public NextId() {
    const r = parseInt(this._IsOverCost ? this.NextOverCostId() : this.NextNormalId());
    return Math.abs(r);
  }

  public get id() {
    return this.NextId();
  }
  public get sid() {
    return this.NextId().toString();
  }
}

export const iyq = 1000,
  /** 雪花算法Genid的实体 */
  unid = new Genid(),
  /** number string 的数组 */
  nsa = ["number", "string"] as const,
  /** 基础数据类型的数组 */
  basics = ["string", "number", "bigint", "boolean", "symbol", "undefined", "function", "null", "date"] as const,
  /** 一天的秒数 */
  daySeconds = 86400,
  /** 一天的微秒 */
  dayMilliseconds = 86400000,
  /** 默认时间 2020-01-01 00:00:00 */
  defDate = new Date("2020-01-01"),
  mimeType = {
    html: ["html", "htm", "shtml"],
    text: ["css", "xml", "mml", "txt", "jad", "wml", "htc"],
    img: ["xbm", "tif", "jfif", "ico", "tiff", "gif", "svg", "jpeg", "svgz", "jpg", "webp", "png", "bmp", "pjp", "apng", "pjpeg", "avif", "wbmp", "jng"],
    audio: ["mid", "midi", "kar", "mp3", "ogg", "m4a", "ra", "aac"],
    video: ["3gpp", "3gp", "mp4", "mpeg", "mpg", "mov", "webm", "flv", "m4v", "mng", "asf", "wmv", "avi"],
    tjs: ["js", "mjs"],
  } as const,
  cache: { [k: string]: { t: number; d: any; c: { resolve: cbk; reject: cbk; }[]; }; } = {},
  ncs: cbk[] = [],
  bus: Array<(time: number) => Promise<void>> = [
    async (t: number) => {
      Object.keys(cache).forEach(k => {
        const c = cache[k], isUndefined = typeof c.d === "undefined";
        if (t > c.t) {
          delete cache[k];
        }
        if (isUndefined) {
          c.t = t + iyq;
        } else {
          c.c.splice(0).forEach(f => { try { f.resolve(c.d); } catch (_) { } });
        }
      });
    },
    async () => { ncs.splice(0).forEach(async (f) => { try { await f(); } catch (_) { } }); }
  ];
export type Basics = (typeof basics)[number];
export type Ns = typeof nsa[number];
Object.assign(globalThis, { cache });
function _next(pf: cbk) {
  return ncs.push(pf);
}
function __next(pf?: Function) {
  return new Promise<void>(async (resolve) => {
    pf && await pf();
    _next(resolve);
  });
}
/** 等待队列
 * @param pf 当参数为Function时,先执行pf,完成后等待下一次再返回;当pf为数字时,等待指定次数再返回,默认为1;
 */
export async function next(pf?: Function | number) {
  if (isNumber(pf)) {
    for (let i = 0; i < pf; i++) {
      await __next();
    }
  } else {
    await __next(pf);
  }
}
/** 当前没有缓存 返回tru,表示新增加了一个等待队列 */
export function addCache(md5: string, resolve: cbk, reject: cbk, timeout = iyq) {
  const c = cache[md5], t = new Date().getTime() + timeout;
  if (c) {
    c.c.push({ resolve, reject });
    c.t = t;
    if (typeof c.d !== "undefined") { execCache(md5, c.d); }
    return false;
  }
  cache[md5] = { t, d: undefined, c: [{ resolve, reject }] };
  return true;
}
export function execCache(md5: string, data: any, isReject?: any, timeout = iyq) {
  const c = cache[md5];
  if (isReject) { delete cache[md5]; }
  if (c) {
    c.d = data;
    const rc = c.c.splice(0);
    isReject
      ? rc.forEach(f => { try { f.reject(c.d); } catch (_) { } })
      : rc.forEach(f => { try { f.resolve(c.d); } catch (_) { } });
    c.t = new Date().getTime() + timeout;
  }
}
/** 事件总线 */
setInterval(() => {
  const t = new Date().getTime();
  bus.forEach(f => { try { f(t); } catch (_) { } });
}, 100);

function cmpKeys(a: string[], b: string[]) {
  let l = a.length;
  if (l === b.length) {
    while (l-- && a[l] === b[l]) {
    }
    return !!l;
  }
  return false;
}
/** obj类型的数据比较,相等返回true; 当sure为false时,只要v1里对应key的值等于v2对应的值,则返回true; 当sure为false时,需要二者完全相等 */
export function objCompare(v1: any, v2: any, sure?: any) {
  if (v1 && v2) {
    try {
      const keys = Object.keys(v1), v2k = Object.keys(v2), l = keys.length;
      if (sure && !cmpKeys(keys, v2k)) {
        return false;
      }
      if (basics.includes(typeof v1 as any)) {
        return v1 == v2;
      }
      if (!l) {
        if (Object.keys(v2).length) {
          return false;
        }
        if (type(v1) === type(v2)) {
          if (nsa.includes(typeof v1 as any)) {
            return v1 === v2;
          }
          return true;
        }
        return false;
      }

      for (let i = 0; i < l; i++) {
        if (!objCompare(v1[keys[i]], v2[keys[i]], sure)) {
          return false;
        }
      }
      return true;
    } catch (error) { }
  }
  return v1 === v2;
}
export function cmpObj(v1: any, v2: any) {
  if (isNS(v1) && isNS(v2)) {
    return v1.toString() === v2.toString();
  }
  if (type(v1) == "date" || type(v2) == "date") {
    return new Date(v1).getTime() === new Date(v2).getTime();
  }
  return JSON.stringify(v1) === JSON.stringify(v2);
}
/** 取对象不同属性;只判定一层,不进行深度判定,值不一致时则返回dist对应key
 * @param source  比较源
 * @param dist    比较值
 * @param isdist  是否以dist的key进行比较
 * @returns 比较出现不同返回不同的字段,否则返回空
 */
export function objDiff(source?: obj, dist?: obj, isdist?: any): undefined | obj {
  const ret: obj = {};
  try {
    if (source && dist) {
      Object.keys(isdist ? dist : source).forEach(k => {
        if (!cmpObj(source[k], dist[k])) {
          ret[k] = dist[k];
        }
      });
      if (Object.keys(ret).length) {
        return ret;
      }
    }
  } catch (_) { }
}
/** 从数组中查找符合条件的数据;
 * @param {Array<T>} arr 需要查找的数组
 * @param {Partial<T>} val 待查找的数据
 * @param {T[Key<T>]} retKey 返回数据字段
 * @param {any} whole 待查找的数据是否完全与数组的数据匹配
 * @returns {((Key<T>) | T)[] | undefined} 返回查找内容
 */
export function arrFind<T extends obj, K extends Key<T>>(arr: Array<T>, val: Partial<T>, retKey: K, whole?: any): T[K][] | undefined;
export function arrFind<T extends obj>(arr: Array<T>, val: Partial<T>, retKey?: Key<T>, whole?: any): T[] | undefined;
export function arrFind<T extends obj>(arr: Array<T>, val: Partial<T>, retKey?: Key<T>, whole?: any): (T[Key<T>] | T)[] | undefined {
  if (Array.isArray(arr)) {
    for (let i = 0; i < arr.length; i++) {
      if (objCompare(val, arr[i], whole)) return [retKey ? arr[i][retKey] : arr[i]];
      if (Array.isArray(arr[i].children)) {
        const t = arrFind(arr[i].children, val, retKey, whole);
        if (t) {
          t.unshift(retKey ? arr[i][retKey] : arr[i]);
          return t;
        }
      }
    }
  }
}
/** 简化的arrFind
 * @param {Array<T>} arr 需要查找的数组
 * @param {Partial<T>} val 待查找的数据
 * @param {any} index 是否返回查找的数据下标
 * @returns {number | T | undefined} 返回查找内容
 */
export function arrFind2<T extends obj>(arr: Array<T>, val: Partial<T>): T | undefined;
export function arrFind2<T extends obj>(arr: Array<T>, val: Partial<T>, index: false): T | undefined;
export function arrFind2<T extends obj>(arr: Array<T>, val: Partial<T>, index: 0): T | undefined;
export function arrFind2<T extends obj>(arr: Array<T>, val: Partial<T>, index: ""): T | undefined;
export function arrFind2<T extends obj>(arr: Array<T>, val: Partial<T>, index: any): number | undefined;
export function arrFind2<T extends obj>(arr: Array<T>, val: Partial<T>, index?: any): T | number | undefined {
  if (typeof val == "object" && Array.isArray(arr)) {
    for (let i = 0; i < arr.length; i++) {
      if (objCompare(val, arr[i])) return index ? i : arr[i];
      if (Array.isArray(arr[i].children)) {
        let t = arrFind2(arr[i].children, val, index);
        if (t) {
          return t;
        }
      }
    }
  }
  if (index) return -1;
}
/** 查找树形数据
 * @param {Tree<T>} arr 需要查找的树形数组
 * @param {T} v 待查询的元素 
 * @param {((el: T) => void) | undefined} callbackfn 每个便利均会运行的回调函数
 * @returns {T[] | undefined} 查询结果,如果查询到 将返回结果,否则返回undefined
 */
export function findTreeValue<T extends { children?: T[]; }>(arr: T[], v: T, callbackfn?: (el: T) => void): T[] | undefined {
  if (Array.isArray(arr)) {
    const ret: T[] = [], b = callbackfn instanceof Function;
    try {
      arr.forEach(e => {
        try { b && callbackfn(e); } catch (_) { }
        if (e === v) {
          ret.unshift(e);
          if (!b) { throw null; }
        } else if (e.children) {
          const r = findTreeValue(e.children, v, callbackfn);
          if (r && r.length) {
            ret.push(e, ...r);
            if (!b) { throw null; }
          }
        }
      });
    } catch (e) {
      if (e) { console.error(e); }
    }
    if (ret.length) { return ret; }
  }
}
export function getValueByPath(obj: any, path?: string) {
  if (path && path.length) {
    // 将路径字符串按 '.' 和 '[' 分割成数组
    const keys = path.split(/[\.\[\]]+/).filter(key => key !== '');
    // 递归遍历对象
    return keys.reduce((acc, key) => {
      if (acc && acc.hasOwnProperty(key)) {
        return acc[key];
      }
      return undefined;
    }, obj);
  }
  return obj;
}
/** 查找树形数组
 * @param arr 需要查找的数组
 * @param predicate 待查找的数组成员 或 回调函数
 * @param retKey 要返回的成员所在的下标;
 * @param callbackfn 遍历每个成员时的回调函数;如果提供的值是Function则会遍历所有成员
 * @returns 查询符合条件的树形数组下标
 */
export function findTree<T extends obj>(arr: T[], predicate: T | ((el: T) => any), retKey: "#index", callbackfn?: (el: T) => void): number[];
/** 查找树形数组
 * @param arr 需要查找的数组
 * @param predicate 待查找的数组成员 或 回调函数
 * @param retKey "#frist" 返回第一个符合条件的成员
 * @param callbackfn 遍历每个成员时的回调函数;如果提供的值是Function则会遍历所有成员
 * @returns 第一个符合条件的成员
 */
export function findTree<T extends obj>(arr: T[], predicate: (el: T) => any, retKey: "#frist", callbackfn?: (el: T) => void): T;
/** 查找树形数组
 * @param arr 需要查找的数组
 * @param predicate 待查找的数组成员 或 回调函数
 * @param retKey 要返回的成员属性名;
 * @param callbackfn 遍历每个成员时的回调函数;如果提供的值是Function则会遍历所有成员
 * @returns 返回符合要求的成员属性值数组
 */
export function findTree<T extends obj, K extends Key<T>>(arr: T[], predicate: (el: T) => any, retKey: K, callbackfn?: (el: T) => void): Array<T[K]>;
/** 查找树形数组
 * @param arr 需要查找的数组
 * @param predicate 待查找的数组成员 或 回调函数
 * @param retKey 要返回的成员属性名;
 * @param callbackfn 遍历每个成员时的回调函数;如果提供的值是Function则会遍历所有成员
 * @returns 返回符合要求的成员属性值数组
 */
export function findTree<T extends obj>(arr: T[], predicate: (el: T) => any, retKey?: string, callbackfn?: (el: T) => void): T[];
/** 查找树形数组
 * @param arr 需要查找的数组
 * @param predicate 待查找的数组成员 或 回调函数
 * @param resultFormat 返回数据的格式化回调 
 * @param callbackfn 遍历每个成员时的回调函数;如果提供的值是Function则会遍历所有成员
 * @returns 未找到符合条件的数据 返回 undefined
 */
export function findTree<T extends obj, R>(arr: T[], predicate: T | ((el: T) => any), retKey?: string | ((el: T) => R), callbackfn?: (el: T) => void): R[];
/** 查找树形数组
 * @param arr 需要查找的数组
 * @param predicate 待查找的数组成员 或 回调函数
 * @param retKey 要返回的成员下标; 如果不提供,则返回成员本身;如果 传参"#index" 则返回成员本身的下标数组;如果传参 "#frist" 则返回第一个符合条件的数据
 * @param callbackfn 遍历每个成员时的回调函数;如果提供的值是Function则会遍历所有成员
 * @returns 未找到符合条件的数据 返回 undefined
 */
export function findTree<T extends obj, K extends Key<T>, R>(arr: T[], predicate: T | ((el: T) => any), retKey?: string | ((el: T) => R), callbackfn?: (el: T) => void) {
  if (Array.isArray(arr)) {
    const ret: Array<T | K | R | number> = [],
      b = callbackfn instanceof Function,
      c = predicate instanceof Function ? predicate : (p: T) => p === predicate,
      d = typeof retKey === "string" ? (el: T) => getValueByPath(el, retKey) : (retKey || ((e) => e));
    for (let i = 0; i < arr.length; i++) {
      const e = arr[i];
      if (c(e)) {
        switch (retKey) {
          case "#index":
            ret.unshift(i);
            break;
          case "#frist":
            return e;
          default:
            ret.unshift(d(e));
            break;
        }
        if (b) { callbackfn(e); } else { break; }
      } else if (e.children) {
        const r = findTree(e.children, c, retKey, callbackfn);
        if (r) {
          switch (retKey) {
            case "#index":
              ret.push(i);
              break;
            case "#frist":
              return r;
            default:
              ret.push(d(e));
              break;
          }
          ret.push(...r);
          if (!b) { break; }
        }
      }
    }
    if (ret.length) { return ret; }
  }
}
/** 获取数据类型 */
export function type(p: any): string {
  const t = typeof p;
  if (t != "object") {
    return t;
  }
  try {
    return p.constructor.name.toLowerCase();
  } catch (error) { }
  return "null";
}
/** 比较两个数据的数据类型是否相同 */
export function cmpType<T>(p1: any, p2: T): p1 is typeof p2 {
  return type(p1) === type(p2);
}
/** 删除p的所有成员,类似p={};但是不改变p的指针 */
export function del(p: any) {
  let ks = Object.keys(p),
    k: any;
  while ((k = ks.pop())) {
    if (basics.indexOf(type(p[k]) as any) >= 0) {
      delete p[k];
    } else {
      del(p[k]);
      delete p[k];
    }
  }
}
/** 取字符串的真实数据长度,汉字占用3个字节? */
export function strLen(str: string) {
  let l = str.length,
    n = l,
    t;
  for (let i = 0; i < l; i++) {
    t = str.charCodeAt(i);
    if (t < 0 || t > 255) n++;
  }
  return n;
}
/** 将树形数据格式化成数组 */
export function tree2arr<T extends obj>(param?: Tree<T> | TreeEle<T>, idKey?: string, childrenKey?: string): Tree<T> {
  if (!idKey) { idKey = "id"; }
  if (!childrenKey) { childrenKey = "children"; }

  const ret: Tree<T> = [];
  if (Array.isArray(param)) {
    param.forEach(e => {
      if (Array.isArray(e.children)) {
        tree2arr(e[childrenKey as string], idKey, childrenKey).forEach(ee => {
          pushArr(ret, ee, idKey as string);
        });
      }
      pushArr(ret, e, idKey as string);
    });
  } else if (isObj(param)) {
    pushArr(ret, param, idKey);
    tree2arr([param], idKey, childrenKey).forEach(e => {
      pushArr(ret, e, idKey as string);
    });
  }
  return ret;
}
/** 保持某个字段的唯一性进行 push */
export function pushArr<T extends obj>(arr: Array<T>, ele: T, idStr = "id") {
  const e = arr.find(eee => { return eee[idStr] == ele[idStr]; });
  if (e) {
    Object.assign(e, ele);
  } else {
    arr.push(ele);
  }
  return arr;
}
/** 获取树形数据的所有子成员 */
export function getTreeChildrens<T>(c: Tree<T>, idStr?: string): Tree<T> {
  const ret: Tree<T> = [], id = idStr ? idStr : "id";
  if (Array.isArray(c)) {
    c.forEach(e => {
      if (Array.isArray(e.children)) {
        getTreeChildrens(e.children, id).forEach(ee => {
          pushArr(ret, ee, id);
        });
      }
      pushArr(ret, e, id);
    });
  }
  return ret;
}
export function getChildrens<T>(c?: TreeEle<T>, key?: string) {
  const ret: T[] = [];
  if (c) {
    ret.push(c);
    if (Array.isArray(c.children)) {
      c.children.forEach(e => {
        ret.push(...getChildrens(e));
      });
    }
  }
  return key ? ret.map(e => e[key]) : ret;
}
/** 数组到树形数据 */
export function arr2tree<T extends obj>(arr: T[], idStr?: string, pidStr?: string, init?: any): Tree<T> {
  const r: Tree<T> = [], hash: { [k: string]: TreeEle<T>; } = {}, id = idStr ? idStr : "id", pid = pidStr ? pidStr : "pid";
  arr.forEach(e => {
    if (Array.isArray(e.children)) {
      const children = e.children;
      if (init) {
        // @ts-ignore
        e.children = [];
      }
      getTreeChildrens(children, id).forEach(ee => {
        hash[e[id]] = ee;
      });
    } else {
      // @ts-ignore
      e.children = [];
    }
    hash[e[id]] = e as (TreeEle<T>);
  });
  arr.forEach(e => {
    const hashVP = hash[e[pid]];
    pushArr(hashVP && Array.isArray(hashVP.children) ? hashVP.children : r, e, id);
  });
  return r;
}
/** 获取id为参数id的属性数据的所有子成员id */
export function getTreeID<T extends Ns>(tree: Array<any>, id: T, key = "pid") {
  let ret: T[] = [];
  for (let i = 0; i < tree.length; i++) {
    if (tree[i].id == id) {
      if (tree[i][key]) {
        ret = getTreeID(tree, tree[i][key], key);
      }
      ret.push(id);
      break;
    }
  }
  return ret;
}
/** 安全的 JSON.parse */
export function strParse<T>(p: any, def?: T): T {
  try {
    return JSON.parse(p);
  } catch (error) {
    // @ts-ignores
    return typeof p == "string" ? (arguments.length > 1 ? def : {}) : p;
  }
}
/** 根据 key只的属性 进行 join组合 */
export function kJoin(arr: Array<any>, key = "name", con = "-") {
  let t = "";
  if (arr instanceof Array) {
    for (let i = 0; i < arr.length; i++) {
      t += con + arr[i][key];
    }
    t = t.substring(1);
  }
  return t;
}
/** 将所有source的成员添加到dist里去.等价于 dist.push(...source) */
export function arrAdd(dist: Array<any>, source: Array<any>) {
  if (Array.isArray(dist) && Array.isArray(source) && source.length > 0) {
    source.forEach((a) => {
      dist.push(a);
    });
  }
  return dist;
}
/** 向p前方添加n个s的字符串 */
export function prefix0(p: string | number, n = 2, s: number | string = "0") {
  let r = p.toString();
  s = s.toString();
  if (isNS(r) && isNS(s)) {
    while (r.length < n) {
      r = s + r;
    }
  }
  return r;
}
/** 将参数转化成Date类型 */
export function snd2Date(p?: string | number | Date) {
  if (!p) {
    p = new Date();
  }
  if (!(p instanceof Date)) {
    if (isNumber(p) && p.toString().length <= 10) {
      p = parseInt(p) * iyq;
    }
    p = new Date(p);
  }
  return p;
}
/** 格式化时间日期 代表天的是大写D而非小写d */
export function formatDate(p?: string | number | Date, formatter?: string) {
  if (!p || p.toString().length < 2) { return "-"; }
  let d = snd2Date(p),
    ret = formatter ? formatter : "yyyy-MM-DD HH:mm:ss";
  const time = {
    /** 年 */
    Y: d.getFullYear(),
    /** 月 */
    M: d.getMonth() + 1,
    /** 日 */
    D: d.getDate(),
    /** 时 */
    H: d.getHours(),
    /** 分 */
    m: d.getMinutes(),
    /** 秒 */
    s: d.getSeconds(),
    /** 毫秒 */
    ms: d.getMilliseconds(),
    /** 周 */
    w: d.getDay(),
  };
  ret = ret.replace(/[y]+/ig, (a: string) => { // 年
    return time.Y.toString().substring(4 - a.length);
  });
  ret = ret.replace(/[M]+/g, (a: string) => { // 月
    return time.M.toString().padStart(a.length, "0");
  });
  ret = ret.replace(/[D]+/g, (a: string) => { // 日
    return time.D.toString().padStart(a.length, "0");
  });
  ret = ret.replace(/[H]+/ig, (a: string) => { // 时
    return time.H.toString().padStart(a.length, "0");
  });
  ret = ret.replace(/[m]+/g, (a: string) => { // 分
    return time.m.toString().padStart(a.length, "0");
  });
  ret = ret.replace(/[s]+/g, (a: string) => { // 秒
    return time.s.toString().padStart(a.length, "0");
  });
  ret = ret.replace(/[S]+/g, (a: string) => { //毫秒
    return time.ms.toString().padStart(a.length, "0");
  });
  ret = ret.replace(/[w]+/g, (a: string) => { // 星期
    const weeks = ["日", "一", "二", "三", "四", "五", "六"];
    return `${a.length > 1 ? "星期" : ""}${weeks[time.w]}`;
  });
  return ret;
}
/** 事件日期转化成UTC秒数 */
export function date2int(p: string | Date) {
  return parseInt(snd2Date(p).getTime() / iyq);
}
/** 取时间戳中 的日期 */
export function t2d(time: number | string | Date) {
  return Math.ceil((snd2Date(time).getTime() - new Date().getTime()) / dayMilliseconds);
}
/** 返回当前日期 加上 day天数后的时间戳 */
export function d2t(day: number) {
  return new Date().getTime() + day * dayMilliseconds;
}
/** 计算两个时间相差的天数 */
export function daysBetweenTimestamp(time1: string | number | Date, time2: string | number | Date) {
  const a = snd2Date(time1), b = snd2Date(time2);
  return Math.ceil((a.getTime() - b.getTime()) / dayMilliseconds);
}
/** 获取随机字符串 */
export function randStr(prefix = "", len = 32) {
  let ret = prefix.toString(), t: any;
  while (ret.length < len) {
    t = Math.floor(Math.random() * 126) + 1;
    ret += String.fromCharCode(t);
  }
  return ret.substring(0, len);
}
/** 字符串转字符流 */
export function s2ab(s: any) {
  if (typeof ArrayBuffer !== "undefined") {
    let buf = new ArrayBuffer(s.length);
    let view = new Uint8Array(buf);
    for (let i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
    return buf;
  } else {
    let buf = new Array(s.length);
    for (let j = 0; j != s.length; ++j) buf[j] = s.charCodeAt(j) & 0xff;
    return buf;
  }
}
/** 任意数据转字符串化,主要是转化为JSON.stringify; */
export function tostr(param: any): string {
  let t = "";
  if (param) {
    switch (typeof t) {
      case "string":
        t = param;
        break;
      case "bigint":
        t = BigInt(param).toString();
        break;
      default:
        t = JSON.stringify(t);
        break;
    }
  } else if (typeof t == "number") t = "0";
  return t;
}
/** 取整数部分;输入不是正数则返回0 */
export function touint(param: any) {
  const t = parseInt(param as string);
  return t > 0 ? t : 0;
}
/** async下的 延迟 */
export function sleep(millisecond: number | string): Promise<number> {
  return new Promise((resolve) => {
    const time = touint(millisecond);
    if (time > 0) {
      const handle = setTimeout(() => {
        clearTimeout(handle);
        resolve(time);
      }, time);
    } else resolve(time);
  });
}
/** 类似parseint 但是会将nan变为0返回 */
export function toInt(param: any) {
  const r = parseInt(param);
  return r ? r : 0;
}
/** 数组转Uint8Array */
export function createUint8Array(source: number[], distLen?: number) {
  const sl = Object.keys(source).length;
  if (!source || !sl) {
    return new Uint8Array();
  }
  if (!distLen || !(distLen > 0)) {
    distLen = sl;
  }
  const ret = new Uint8Array(distLen),
    l = sl < distLen ? sl : distLen;
  for (let i = 0; i < l; i++) {
    ret[i] = toInt(source[i]);
  }
  return ret;
}
/** 具有深度的克隆数据,与cp不同的是,防止js无限引用导致的JSON.stringify报错 */
export function clo<T>(p: T, _deep?: number): T {
  const deep = (!_deep && typeof _deep === "undefined" ? 3 : _deep) - 1;
  if (deep >= 0) {
    if (Array.isArray(p)) {
      return p.map((e) => { return clo(e, deep); }) as any;
    } else if (p && typeof p == "object") {
      if (p instanceof Uint8Array) {
        return cloneUint8Array(p) as any;
      }
      if (isObj(p)) {
        const k = Object.keys(p), l = k.length, r: obj = {};
        if (l > 0) {
          k.forEach((e) => {
            r[e] = clo(p[e], deep);
          });
        }
        return r as any;
      }
    }
  }
  return p;
}
/** 将s的所有成员根据deep限制的前提下赋值给t,不同于Object.assign的地方是具有深度 */
export function assign<T, S>(t: T, s: S, _deep?: number): T & S {
  const deep = (!_deep && typeof _deep === "undefined" ? 1 : _deep) - 1;
  if (deep >= 0) {
    if (isArr(t)) {
      t.splice(0);
      if (isArr(s)) {
        t.push(...s);
      }
    } else if (t instanceof Uint8Array && s instanceof Uint8Array) {
      if (t.length == s.length) {
        for (let i = 0; i < t.length; i++) {
          t[i] = s[i];
        }
      } else {
        return s as any;
      }
    } else if (isObj(t) && isObj(s)) {
      Object.keys(s).forEach(k => {
        const te = t[k], se = s[k];
        t[k] = isObj(te) && isObj(se) ? assign(te, se, deep) : se;
      });
    } else {
      if (type(s) != "undefined") {
        return s as any;
      }
    }
  }
  return t as T & S;
}
/** 执行eval,防止浏览器报错 */
export function mevl(funStr: string): any { return meval(funStr); }
/** 具有异常避免的执行eval */
export function evalDef<T = any>(str: string, def: T): T {
  return meval(str, def) as T;
}
const
  nativeMap: MapConstructor = evalDef("Map", function () { } as any),
  nativeSet: SetConstructor = evalDef("Set", function () { } as any),
  nativePromise: PromiseConstructor = evalDef("Promise", function () { } as any);
/** 获取o的属性名 */
export function objToStr(o: any) { return Object.prototype.toString.call(o); }
/** 是否Date类型 */
export function isDate(o: any): o is Date { return o instanceof Date; }
/** 是否数字,字符串数字也返回true */
export function isNumber(p: any): p is number { return /^-?\d+(\.\d+)?$/.test(`${p}`); }
/** 是否整数,字符串数字也返回true */
export function isInt(p: any): p is number { return isNumber(p) && parseInt(p) == p; }
/** 是否正整数 */
export function isUint(p: any): p is number { return isInt(p) && p > 0; }
/** 是否字符串 */
export function isString(p: any): p is string { return typeof p === "string"; }
/** 是否字符串且不为"" */
export function isStringT(p: any): p is string { return typeof p === "string" && !!p.length; }
/** 是否数字或者字符串 */
export function isNS(p: any): p is number | string { try { return p.toString() == p; } catch (error) { return false; } }
/** 是否数字或者字符串,且 当为数字时不为0,当为字符串时不为"" */
export function isNst(p: any): p is number | string { return isNS(p) && !!p; }
/** 是否为空 */
export function isNull(p: any): p is undefined | null { return !p && p !== 0 && p !== ""; }
/** 是否Obj类型 */
export function isObj(p: any): p is Object { return type(p) == "object"; }
/** 是否数组 */
export function isArr(p: any): p is Array<any> { return Array.isArray(p); }
/** 是否数组 */
export function isArrT(p: any, min = 1): p is Array<any> { return Array.isArray(p) && p.length >= min; }
/** 是否正则表达式 */
export function isRegExp(o: any): o is RegExp { return typeof o === 'object' && objToStr(o) === '[object RegExp]'; }
/** 是否是Map类型 */
export function isMap(o: any): o is Map<any, any> { return o instanceof nativeMap; }
/** 是否为原生设置 */
export function isSet(o: any): o is Set<keyof typeof o> { return o instanceof nativeSet; }
/** 是否Promise */
export function isPromise(o: any): o is Promise<any> { return o instanceof nativePromise; }
/** 获取RegExp的标志 */
export function getRegExpFlags(re: RegExp) {
  let flags = '';
  if (re.global) flags += 'g';
  if (re.ignoreCase) flags += 'i';
  if (re.multiline) flags += 'm';
  return flags;
}
/** 克隆数据,不同于clo的地方是错误更少,但效率更低 */
export function clone<T = any>(parent: T, circular?: any, depth?: number, prototype?: any, includeNonEnumerable?: any): T {
  if (isObj(circular)) {
    depth = circular.depth;
    prototype = circular.prototype;
    includeNonEnumerable = circular.includeNonEnumerable;
    circular = circular.circular;
  }
  const allParents: any[] = [];
  const allChildren: any[] = [];
  const useBuffer: boolean = mevl("try{return typeof Buffer!='undefined';}catch{}return false;");
  if (typeof circular == 'undefined') {
    circular = true;
  }
  if (!(depth && depth > 0)) {
    // depth = Infinity;
    depth = 100;
  }
  function _clone(parent: any, _depth: number) {
    if (parent === null) {
      return null;
    }
    if (_depth === 0) {
      return parent;
    }
    let
      child: RegExp | never[] | Buffer | Uint8Array | Map<any, any> | Set<any> | Promise<any> | Date,
      proto: any;
    if (typeof parent != 'object') {
      return parent;
    }
    if (isMap(parent)) {
      const c = child = new nativeMap();
      parent.forEach(function (value: any, key: any) {
        const keyChild = _clone(key, _depth - 1);
        const valueChild = _clone(value, _depth - 1);
        c.set(keyChild, valueChild);
      });
    } else if (isSet(parent)) {
      const c = child = new Map();
      parent.forEach((v: any, k: any) => {
        const entryChild = _clone(v, _depth - 1);
        if (c.set) c.set(k, entryChild);
        else if ((c as any).add) (c as any).add(entryChild);
      });
    } else if (isPromise(parent)) {
      child = new nativePromise(function (resolve, reject) {
        parent.then(function (value: any) {
          resolve(_clone(value, _depth - 1));
        }, function (err: any) {
          reject(_clone(err, _depth - 1));
        });
      });
    } else if (isArr(parent)) {
      child = [];
    } else if (isRegExp(parent)) {
      child = new RegExp(parent.source, getRegExpFlags(parent));
      if (parent.lastIndex) child.lastIndex = parent.lastIndex;
    } else if (isDate(parent)) {
      child = new Date(parent.getTime());
    } else if (useBuffer && Buffer.isBuffer(parent)) {
      if (Buffer.from) {
        child = Buffer.from(parent);
      } else {
        child = new Buffer(parent.length);
        parent.copy(child);
      }
      return child;
    } else if (parent && parent instanceof Error) {
      child = Object.create(parent);
    } else {
      if (typeof prototype == 'undefined') {
        proto = Object.getPrototypeOf(parent);
        child = Object.create(proto);
      } else {
        child = Object.create(prototype);
        proto = prototype;
      }
    }

    if (circular) {
      const index = allParents.indexOf(parent);
      if (index != -1) {
        return allChildren[index];
      }
      allParents.push(parent);
      allChildren.push(child);
    }

    for (const i in parent) {
      const attrs = Object.getOwnPropertyDescriptor(parent, i);
      if (attrs) {
        child[i] = _clone(parent[i], _depth - 1);
      }
    }
    if (Object.getOwnPropertySymbols) {
      const symbols = Object.getOwnPropertySymbols(parent);
      for (let i = 0; i < symbols.length; i++) {
        const symbol = symbols[i];
        const descriptor = Object.getOwnPropertyDescriptor(parent, symbol);
        if (descriptor && descriptor.enumerable) {
          child[symbol] = _clone(parent[symbol], _depth - 1);
          Object.defineProperty(child, symbol, descriptor);
        }
      }
    }
    if (includeNonEnumerable) {
      const allPropertyNames = Object.getOwnPropertyNames(parent);
      for (let i = 0; i < allPropertyNames.length; i++) {
        const propertyName = allPropertyNames[i];
        const descriptor = Object.getOwnPropertyDescriptor(parent, propertyName);
        if (descriptor && descriptor.enumerable) {
          child[propertyName] = _clone(parent[propertyName], _depth - 1);
          Object.defineProperty(child, propertyName, descriptor);
        }
      }
    }

    return child;
  }
  return _clone(parent, depth);
}
/** 简单的数学计算 */
export const math = {
  getBigInt(p: any) {
    try { return BigInt(p); } catch (error) { return BigInt(0); }
  },
  getBigInts(p: any[]) {
    return p.map(math.getBigInt);
  },
  abs(p: any) {
    const r = math.getBigInt(p).toString();
    return r.indexOf("-") ? r : r.substring(1);
  },
  add(...arg: any[]) {
    const r = math.getBigInts(arg).reduce((a, b) => { return a + b; }).toString(),
      l = r.length,
      t = r.replaceAll(/[a-z]/ig, "");
    return l && l === t.length ? r : "0";
  },
  sub(...arg: any[]) {
    const r = math.getBigInts(arg).reduce((a, b) => { return a - b; }).toString(),
      l = r.length,
      t = r.replaceAll(/[a-z]/ig, "");
    return l && l === t.length ? r : "0";
  },
  mul(...arg: any[]) {
    const r = math.getBigInts(arg).reduce((a, b) => { return a * b; }).toString(),
      l = r.length,
      t = r.replaceAll(/[a-z]/ig, "");
    return l && l === t.length ? r : "0";
  },
  div(...arg: any[]) {
    const r = math.getBigInts(arg).reduce((a, b) => { return a / b; }).toString(),
      l = r.length,
      t = r.replaceAll(/[a-z]/ig, "");
    return l && l === t.length ? r : "0";
  },
  decdiv(dec: number, ...arg: any[]) {
    if (!(dec > 0)) { dec = 0; }
    let ret = "1", l = dec;
    while (l-- > 0) {
      ret += "0";
    }
    const d = math.getBigInt(ret);
    ret = "0";
    if (arg && arg.length > 1) {
      const t = arg.map(math.getBigInt);
      t[0] *= d;
      ret = t.reduce((a, b) => a / b).toString();
      l = ret.length;
      ret = ret.replaceAll(/[a-z]/ig, "");
      if (l !== ret.length) ret = "0";
    }
    if (dec) {
      l = ret.length;
      while (l <= dec) {
        l++;
        ret = "0" + ret;
      }
      l -= dec;
      ret = ret.substring(0, l) + "." + ret.substring(l);
    }
    return ret;
  },
  rem(...arg: any[]) {
    const r = math.getBigInts(arg).reduce((a, b) => { return a % b; }).toString(),
      l = r.length,
      t = r.replaceAll(/[a-z]/ig, "");
    return l && l === t.length ? r : "0";
  },
  bitAnd(...arg: any[]) {
    return arg && arg.length ? math.getBigInts(arg).reduce((a, b) => { return a & b; }).toString() : "0";
  },
  bitOr(...arg: any[]) {
    return arg && arg.length ? math.getBigInts(arg).reduce((a, b) => { return a | b; }).toString() : "0";
  },
  bitXor(...arg: any[]) {
    return arg && arg.length ? math.getBigInts(arg).reduce((a, b) => { return a % b; }).toString() : "0";
  },
  bitNot(...arg: any) {
    return (~math.getBigInt(arg)).toString();
  },
  bitShl(...arg: any[]) {
    return arg && arg.length ? math.getBigInts(arg).reduce((a, b) => { return a << b; }).toString() : "0";
  },
  bitShr(...arg: any[]) {
    return arg && arg.length ? math.getBigInts(arg).reduce((a, b) => { return a >> b; }).toString() : "0";
  }
};
/** 克隆Uint8Array */
export function cloneUint8Array(p: Uint8Array | number[] | obj) {
  const d = new Uint8Array(Object.keys(p).length);
  for (let i = 0; i < d.length; i++) {
    if (p[i] >= 0 || p[i] < 0) d[i] = p[i] & 255;
  }
  return d;
}
/** 根据id查找数组 */
export function findById<T extends ki>(arr: Array<T>, id?: string) {
  return id && Array.isArray(arr) ? arr.find(e => { return e.id == id; }) : undefined;
}
/** 根据id查找数组:返回下标 */
export function findIndexById<T extends ki>(arr: Array<T>, id?: string) {
  return id && Array.isArray(arr) ? arr.findIndex(e => { return e.id == id; }) : -1;
}
/** 数字格式化成金额样式,保持小数点两位
 * @param {any}p 要转换的数据
 * @param {any}minus 是否负数
 * @returns {string} 转换后的结果
 */
export function getDisplayMoney(p?: any, minus?: any) {
  const v = (p || 0).toString(), f = v.indexOf("-") ? 0 : 1, s = prefix0(v.substring(f), 3),
    l = s.length, r = `${s.substring(0, l - 2)}.${s.substring(l - 2)}`;
  return minus && !f ? "-" + r : r;
}
/** 将数组的name字段通过|进行拼接 */
export function joinNames(...arg: any) {
  let r = "";
  if (Array.isArray(arg)) {
    const l = arg.length;
    for (let i = 0; i < l; i++) {
      if (Array.isArray(arg[i])) {
        arg[i].forEach((e: { name: string; }) => { r += "|" + e.name; });
        break;
      }
    }
  }
  return r.length ? r.substring(1) : r;
}
/** 删除dist原有的所有属性,使用source的所有属性进行填充 */
export function copyObj<T>(dist?: any, source?: T, saveDist?: any) {
  if (dist && isObj(dist) && source && isObj(source)) {
    if (!saveDist) Object.keys(dist).forEach((k) => delete dist[k as Key<T>]);
    Object.keys(source).forEach(k => {
      dist[k as Key<T>] = source[k as Key<T>];
    });
  }
  return dist;
}
/** 删除dist原有的所有成员,使用source的所有成员进行填充 */
export function copyArr<T extends Array<any>>(dist?: T, source?: T) {
  if (Array.isArray(dist) && Array.isArray(source)) {
    dist.splice(0);
    source.forEach(e => dist.push(e));
  }
  return dist;
}
/** 获取obj的属性值,property的值是以.进行连接的,而不是js中字面量以[]进行连接 */
export function getObjProperty<T>(p: any, property?: string, def?: T) {
  let ret: T = p;
  try {
    if (!property) { property = ""; };
    const a = property.split("."), ps: string[] = [];
    a.forEach(e => {
      if (e) {
        if (/^\[.*\]$/.test(e)) {
          ps.push(e.slice(1, -1));
        } else {
          ps.push(e);
        }
      }
    });
    if (!ps.length) ret = def as T;
    while (ps.length) {
      ret = ret[ps.shift() as string];
    }
    if (typeof ret === "undefined") throw new Error();
  } catch (e) { ret = def as T; }
  return ret;
}
/** 获取Async类型的数据属性值 */
export async function getObjPropertyAsync<T>(p: any, property?: string, def?: T, ...params: any) {
  let ret = getObjProperty(p, property, def);
  try {
    if (ret instanceof Function) {
      ret = await ret(...params);
    }
  } catch (error) { }
  return ret;
}
/** 设置默认值,当dist为undefined|null 或数据类型与source不同时,返回source,否则返回dist */
export function setDefaults<T>(dist: any, source: T) {
  if (isObj(source)) {
    const ret: T = dist ? dist : {};
    for (const k in source) {
      if (Object.prototype.hasOwnProperty.call(source, k)) {
        const s = source[k], d = ret[k];
        ret[k] = isObj(s) ? setDefaults(ret[k], s) : (!isNull(s) && !cmpType(s, d) ? s : d);
      }
    }
    return ret;
  }
  return dist === undefined || dist === null || (!isNull(source) && cmpType(dist, source)) ? source : dist as T;
};
/** 安全的eval
 * @param {string} code 需要运行的字符串代码;如果字符串是个function表达式,则会执行这个function
 * @param {def} def 如果代码执行出错,则返回def
 * @param {any[]} params 需要给代码添加的执行参数
 * @return {T} 返回执行结果
 */
export function meval<T>(code: string, def?: T, ...params: any[]): T | undefined {
  try {
    const r = new Function(`return ${code};`)(...params);
    return r instanceof Function ? r(...params) : r;
  } catch (_) { }
  return def;
}
/** 根据后缀获取文件类型 */
export function mime(path: string) {
  const s = path.substring(path.lastIndexOf(".") + 1);
  for (const key in mimeType) {
    if (mimeType[key].includes(s)) {
      return key as keyof typeof mimeType;
    }
  }
  return "file";
}
const oto = {
  c: 0, a: 0, get t() { return new Date().getTime(); }
};
export function out(data: any, refsh?: any) {
  if (refsh) { oto.c = oto.a = oto.t; }
  console.log([`单步:${(oto.t - oto.c) / iyq} 总:${(oto.t - oto.a) / iyq}`], data);
  oto.c = oto.t;
}
export function formatUrl(url?: string, baseUrl?: string) {
  if (typeof url == "string" && url) {
    if (url.indexOf("data:image") && url.indexOf("http")) {
      if (!baseUrl) {
        baseUrl = "";
      }
      if (!url.startsWith("/")) {
        url = "/" + url;
      }
      url = baseUrl.replace(/\/+$/g, "") + url;
    }
  }
  return url || baseUrl || "";
}
export function existUni() {
  try { return !!uni; } catch (_) { }
  return false;
}
/** 将Uint8Array转换成utf8字符串
 * @param uint8Array 待转换的Uint8Array
 * @returns 转换后的结果
 */
export function uint8ArrayToUtf8String(uint8Array: Uint8Array) {
  let str = '';
  let i = 0;
  while (i < uint8Array.length) {
    const byte1 = uint8Array[i];
    // 1 字节（ASCII）
    if ((byte1 & 0b10000000) === 0) {
      str += String.fromCodePoint(byte1);
      i += 1;
    }
    // 2 字节
    else if ((byte1 & 0b11100000) === 0b11000000) {
      if (i + 1 >= uint8Array.length) break; // 无效（缺少后续字节）
      const byte2 = uint8Array[i + 1];
      if ((byte2 & 0b11000000) !== 0b10000000) break; // 无效（后续字节格式错误）
      const codePoint = ((byte1 & 0b00011111) << 6) | (byte2 & 0b00111111);
      str += String.fromCodePoint(codePoint);
      i += 2;
    }
    // 3 字节
    else if ((byte1 & 0b11110000) === 0b11100000) {
      if (i + 2 >= uint8Array.length) break;
      const byte2 = uint8Array[i + 1];
      const byte3 = uint8Array[i + 2];
      if ((byte2 & 0b11000000) !== 0b10000000 || (byte3 & 0b11000000) !== 0b10000000) break;
      const codePoint = ((byte1 & 0b00001111) << 12) | ((byte2 & 0b00111111) << 6) | (byte3 & 0b00111111);
      str += String.fromCodePoint(codePoint);
      i += 3;
    }
    // 4 字节
    else if ((byte1 & 0b11111000) === 0b11110000) {
      if (i + 3 >= uint8Array.length) break;
      const byte2 = uint8Array[i + 1];
      const byte3 = uint8Array[i + 2];
      const byte4 = uint8Array[i + 3];
      if ((byte2 & 0b11000000) !== 0b10000000 || (byte3 & 0b11000000) !== 0b10000000 || (byte4 & 0b11000000) !== 0b10000000) break;
      const codePoint = ((byte1 & 0b00000111) << 18) | ((byte2 & 0b00111111) << 12) | ((byte3 & 0b00111111) << 6) | (byte4 & 0b00111111);
      str += String.fromCodePoint(codePoint);
      i += 4;
    }
    // 无效字节（如孤立的后续字节）
    else {
      i += 1; // 跳过无效字节（或替换为替换字符）
    }
  }
  return str;
}
/*
IOS不支持正则
(?=pattern)：后面是什么
(?!pattern)：后面不是什么
(?<=pattern)：前面是什么
(?<!pattern)：前面不是什么
*/